package com.mikgonz.farkle.ui;

import java.sql.SQLException;
import java.util.ArrayList;

import android.app.Dialog;
import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.CloseableIterator;
import com.j256.ormlite.dao.Dao;
import com.markupartist.android.widget.ActionBar;
import com.markupartist.android.widget.ActionBar.IntentAction;
import com.mikgonz.farkle.AsyncRPC;
import com.mikgonz.farkle.OnlineSessionListener;
import com.mikgonz.farkle.PushNotifReceiver;
import com.mikgonz.farkle.R;
import com.mikgonz.farkle.ReflectionAction;
import com.mikgonz.farkle.Util;
import com.mikgonz.farkle.database.DatabaseOpenHelper;
import com.mikgonz.farkle.database.Friend;
import com.mikgonz.farkle.database.Request;
import com.mikgonz.farkle.shared.FarkleRequestFactory;
import com.mikgonz.farkle.shared.FriendshipProxy;
import com.mikgonz.farkle.shared.UserProxy;

public class OnlineActivity extends OrmLiteBaseActivity<DatabaseOpenHelper>
		implements OnItemClickListener, DialogInterface.OnClickListener,
		OnlineSessionListener, OnCancelListener {

	public static final int ADD_FRIEND = 1;
	private static final int WAIT_DIALOG = 6;
	private static final int RESPOND_TO_REQUEST_DIALOG = 5;

	private static final String MESSAGE_ID = "messageId";

	public static final String REQUEST_NAME = "name";
	public static final String FROM = "from";

	private ArrayList<Friend> friends;
	private ArrayList<Request> requests;
	private Request requestToBeProcessed;
	private String friendName;
	private UserProxy user;

	private ArrayAdapter<String> mAdapter;
	private MyReceiver mReceiver;
	private DatabaseOpenHelper helper;
	private NewTask task;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.online);

		setUpActionBar();
		populateList();

		final Bundle args = new Bundle();
		args.putBoolean(Util.TO_LISTEN, false);
		args.putInt(MESSAGE_ID, R.string.login_in_progress);
		showDialog(WAIT_DIALOG, args);
		Util.checkSession(this, this);
	}

	@Override
	protected Dialog onCreateDialog(int id, Bundle args) {
		Dialog d = null;

		switch (id) {

		case (WAIT_DIALOG):

			final int messageId = args.getInt(MESSAGE_ID);
			OnCancelListener l = (args.getBoolean(Util.TO_LISTEN)) ? this
					: null;

			d = Util.getProgressDialog(this, messageId, l);
			break;

		case (RESPOND_TO_REQUEST_DIALOG):

			Util.buildAlertDialog(
					OnlineActivity.this,
					getString(R.string.accept_request) + " "
							+ requestToBeProcessed.getName(),
					getString(R.string.accept), OnlineActivity.this,
					getString(R.string.reject), OnlineActivity.this).show();
			break;
		}
		return d;

	}

	@SuppressWarnings("rawtypes")
	private void setUpActionBar() {

		ActionBar bar = (ActionBar) findViewById(R.id.actionbar);

		Intent restart = new Intent(this, Main.class);
		restart.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
				| Intent.FLAG_ACTIVITY_CLEAR_TOP);
		bar.setHomeAction(new IntentAction(this, restart, R.drawable.house));

		// Reflection magic here
		final Intent i = new Intent(this, TextInputDialog.class);
		i.putExtra("title", getString(R.string.enter_name_friend));

		final Class[] klasses = { Intent.class, int.class };
		final String methodName = "startActivityForResult";
		final Object[] params = { i, ADD_FRIEND };

		bar.addAction(new ReflectionAction(R.drawable.add_friend, klasses,
				methodName, this.getClass(), this, params));

	}

	@Override
	protected void onStart() {
		super.onStart();

		IntentFilter iF = new IntentFilter();
		iF.addAction(FarkleRequestFactory.FRIEND_REQUEST_ACCEPTED_ACTION);
		iF.addAction(FarkleRequestFactory.FRIEND_REQUEST_REJECTED_ACTION);
		iF.addAction(FarkleRequestFactory.NEW_FRIEND_REQUEST_ACTION);
		mReceiver = new MyReceiver();
		registerReceiver(mReceiver, iF);

		helper = getHelper();

		Intent i = getIntent();
		String from = i.getStringExtra(REQUEST_NAME);

		if (from == null)
			return;

		Request re = null;
		try {
			re = helper.getRequestDao().queryForId(from);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		if (re == null)
			return;

		showDialog(re);

	}

	@Override
	protected void onStop() {
		super.onStop();
		unregisterReceiver(mReceiver);
	}

	private void populateList() {

		ArrayList<String> items = new ArrayList<String>();
		friends = new ArrayList<Friend>();
		requests = new ArrayList<Request>();

		ListView list = (ListView) findViewById(R.id.friends_list);

		try {
			helper = (DatabaseOpenHelper) OpenHelperManager.getHelper(this);
			Dao<Friend, String> dao1 = helper.getFriendDao();
			CloseableIterator<Friend> i = dao1.closeableIterator();

			while (i.hasNext()) {
				Friend f = i.next();
				friends.add(f);
				items.add(f.getName());
			}

			i.close();

			Dao<Request, String> dao2 = helper.getRequestDao();
			CloseableIterator<Request> i2 = dao2.closeableIterator();

			while (i2.hasNext()) {
				final Request re = i2.next();
				requests.add(re);
				int messageId = re.isIncoming() ? R.string.friends_list_incoming
						: R.string.friends_list_outgoing;

				items.add(getString(messageId) + " " + re.getName());
			}

			i2.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		if (friends.size() == 0 && requests.size() == 0) {
			items.add(getString(R.string.press_menu_4_add));
		} else {
			list.setOnItemClickListener(this);
		}

		mAdapter = new ArrayAdapter<String>(this, R.layout.friend_list_item,
				items);
		list.setAdapter(mAdapter);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if (resultCode != RESULT_OK)
			return;

		friendName = data.getStringExtra(TextInputDialog.TEXT);

		task = new NewTask(getApplicationContext());
		task.execute(AsyncRPC.START_FRIENDSHIP, user.getName(),
				Long.toString(user.getId()), friendName);

		final Bundle args = new Bundle();
		args.putBoolean(Util.TO_LISTEN, true);
		args.putInt(MESSAGE_ID, R.string.please_wait);
		showDialog(WAIT_DIALOG, args);
	}

	public void showDialog(Request re) {

		requestToBeProcessed = re;
		showDialog(RESPOND_TO_REQUEST_DIALOG, null);
	}

	@Override
	public void onItemClick(AdapterView<?> arg0, View view, int position,
			long id) {

		if (position >= friends.size()) {
			position -= friends.size();

			if (requests.get(position).isIncoming())
				showDialog(requests.get(position));

		} else {
			// start a chat with this friend
			Intent i = new Intent(getApplicationContext(), ChatActivity.class);

			final String friendName = friends.get(position).getName();
			final Long serverId = friends.get(position).getServerId();

			i.putExtra(ChatActivity.FRIEND, friendName);
			i.putExtra(ChatActivity.FRIEND_ID, Long.toString(serverId));
			startActivity(i);
		}

	}

	@Override
	public void onClick(DialogInterface dialog, int which) {
		task = new NewTask(OnlineActivity.this);

		String b = (which == DialogInterface.BUTTON_POSITIVE) ? "true"
				: "false";
		task.execute(AsyncRPC.RESPOND_TO_FR,
				Long.toString(requestToBeProcessed.getServerId()), b);

		final Bundle args = new Bundle();
		args.putBoolean(Util.TO_LISTEN, true);
		args.putInt(MESSAGE_ID, R.string.please_wait);
		showDialog(WAIT_DIALOG, args);
	}

	class NewTask extends AsyncRPC {

		public NewTask(Context c) {
			super(c);
		}

		@Override
		protected void onPostExecute(Object result) {
			String action = getAction();
			dismissDialog(WAIT_DIALOG);

			if (action.equals(START_FRIENDSHIP)) {

				handleStartFriendship((FriendshipProxy) result);

			} else if (action.equals(RESPOND_TO_FR)) {

				handleResponseToFriendship((UserProxy) result);

			} else if (action.equals(ERROR)) {

				Toast.makeText(getApplicationContext(), getResources()
						.getString(R.string.error), Toast.LENGTH_LONG);
			}
		}

	}

	private void handleStartFriendship(FriendshipProxy fr) {
		if (fr == null) {
			Toast.makeText(getApplicationContext(),
					getString(R.string.user_null), Toast.LENGTH_SHORT).show();
			return;
		}

		Request outgoing = new Request(fr.getOtherName(), fr.getId(), 0);

		try {
			helper.getRequestDao().create(outgoing);
		} catch (SQLException e) {
			e.printStackTrace();
		}

		populateList();
	}

	private void handleResponseToFriendship(UserProxy result) {

		if (user == null) {
			Toast.makeText(getApplicationContext(),
					getString(R.string.fr_null), Toast.LENGTH_LONG).show();
			return;
		}

		try {
			Dao<Request, String> dao1 = helper.getRequestDao();
			Request re = dao1.queryForId(user.getName());
			dao1.delete(re);

			Dao<Friend, String> dao2 = helper.getFriendDao();
			Friend f = new Friend(user.getName(), user.getId());
			dao2.create(f);

		} catch (SQLException e) {
			e.printStackTrace();
		}

		populateList();
	}

	private class MyReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context c, Intent i) {
			populateList();

			NotificationManager nm = (NotificationManager) c
					.getSystemService(Context.NOTIFICATION_SERVICE);

			nm.cancel(PushNotifReceiver.NOTIF_ID);
		}

	}

	@Override
	public void onSessionLive(UserProxy user) {
		this.user = user;
		dismissDialog(WAIT_DIALOG);
	}

	@Override
	public void onSessionDead() {

		dismissDialog(WAIT_DIALOG);

		Toast.makeText(getApplicationContext(),
				getString(R.string.login_or_register), Toast.LENGTH_SHORT)
				.show();

		startActivity(new Intent(this, OnlineAccount.class));
	}

	@Override
	public void onCancel(DialogInterface arg0) {
		task.cancel(true);
	}
}
